/*
 * FileName : app_fileBuf.c
 *
 * Description : file buffer of FIFO mode.
 *
 * Created on 2016.09.27 by WFL.
 *
 * Revision History:
 *
 */

#include "app_fileBuf.h"



/* locate at FSRAM */
extern uint8_t 	FileBufForTrans[FILE_WHOLE_BUFFER_LEN];
extern uint32_t fileReadPtr;
extern uint32_t fileWritePtr;
extern uint32_t	fileWriteOffset;
extern uint16_t	fileCount;


void initFile(uint32_t addr,uint8_t type,uint32_t fileLen);
uint8_t nextFilePointer(uint32_t *currP,uint32_t otherP,uint8_t eqPermit);
void setfileStatus(uint32_t addr, uint8_t sts);
uint8_t getfileType(uint32_t addr);
uint8_t fileIsValidForTrans(uint32_t addr);
void clearFileHead(uint32_t addr);
uint32_t getFileLength(uint32_t addr);
void setFileLength(uint32_t addr,uint32_t fileLen);
uint8_t creatNewFile(uint8_t type,uint32_t fileLen);

/*
 * @brief  initialize the management variables after power on.
 */
void initFileBuf(void)
{
	fileReadPtr=0;
	fileWritePtr=0;
	fileCount = 0;
	fileWriteOffset=FILEDATAOFFSET;
	clearFileHead(0);
}

/*
 * @brief  write in one data to file each time.
 *         should be called by only one task at the same time.
 */
uint8_t writeInData(uint8_t data,uint8_t type,uint32_t fileLen)
{
	if(fileWriteOffset==FILEDATAOFFSET)		//starting a new file.
	{
		if(creatNewFile(type,fileLen))
			return 1;
	}
	
	if(fileWriteOffset!=FILEDATAOFFSET && type!=getfileType(fileWritePtr))	//the previous file is not finish yet.
	{
		setFileLength(fileWritePtr,fileWriteOffset);	//change the length of the previous file
		setfileStatus(fileWritePtr,FILESAVED);			//ending the previous file with datas that have already received.
		fileWriteOffset = FILEDATAOFFSET;
		if( nextFilePointer(&fileWritePtr,fileReadPtr,1))
			return 3;
		if(creatNewFile(type,fileLen))		//starting a new file
			return 1;
	}
	
	FileBufForTrans[fileWritePtr+fileWriteOffset] = data;	//saving data
	fileWriteOffset++;										//increasing pointer
	
	if(fileWriteOffset>getFileLength(fileWritePtr))//writing pointer is beyong the size of current file.
		return 2;
	
	if(fileWriteOffset==getFileLength(fileWritePtr))//end of current file.
	{	
		setfileStatus(fileWritePtr,FILESAVED);		//file complete setting
		
		fileWriteOffset = FILEDATAOFFSET;
		if( nextFilePointer(&fileWritePtr,fileReadPtr,1))
			return 3;
		return 4;
	}
	
	return 0;
}

/*
 * @brief  creat a new file for writing in
 */
uint8_t creatNewFile(uint8_t type,uint32_t fileLen)
{
	if(type!=0x01&&type!=0x02) 	//type check.
		return 1;				//wrong type
	
	if(!fileIsValidForTrans(fileReadPtr))
	{
		if(fileWritePtr!=fileReadPtr)
			return 2;					//wrong fileReadPtr
		
		initFile(fileWritePtr,type,fileLen);	//return succeed
	}
	else
	{
		if(fileWritePtr==fileReadPtr)
			return 3;					//full, no free space
		
		
		if(fileWritePtr>fileReadPtr)
		{
			if(fileWritePtr+FILE_LEN_MAX <= FILE_WHOLE_BUFFER_LEN)
			{
				initFile(fileWritePtr,type,fileLen);
			}
			else
			{
				fileWritePtr = 0;
				return creatNewFile(type,fileLen);
			}
		}
		else
		{
			if(fileWritePtr+FILE_LEN_MAX <= fileReadPtr)
			{
				initFile(fileWritePtr,type,fileLen);
			}
			else
			{
				return 4;	//full
			}
		}
		
	}
	return 0;
}


/*
 * @brief  currP pointer add by not passing over ther otherP.
 */
uint8_t nextFilePointer(uint32_t *currP,uint32_t otherP,uint8_t eqPermit)
{
	if(*currP >= otherP)
	{
		*currP = *currP + getFileLength(*currP);
		if(*currP+FILE_LEN_MAX <= FILE_WHOLE_BUFFER_LEN)
		{
		}
		else
		{
			*currP = 0;
		}
	}
	else
	{
		*currP = *currP + getFileLength(*currP);
		if(*currP+FILE_LEN_MAX <= otherP)
		{
		}
		else
		{
			return 1;
		}
	}
	return 0;
}

/*
 * @brief  set file length, including Heart and Data part.
 *         set file type.
 *         set fileWriteOffset=FILEDATAOFFSET.
 */
void initFile(uint32_t addr,uint8_t type,uint32_t fileLen)
{
	TSC_FILE* pFile;
	pFile = (TSC_FILE*)(&FileBufForTrans[addr]);
	
	clearFileHead(addr);
	
	pFile->fType = type;
	fileWriteOffset=FILEDATAOFFSET;
	
	fileLen += FILEDATAOFFSET;
	
	setFileLength(addr,fileLen);
	
	pFile->fID_55=0x55;
	pFile->fID_AA=0xAA;
	pFile->fID_66=0x66;
	pFile->fID_BB=0xBB;
	pFile->fID_5A=0x5A;
	pFile->fID_A5=0xA5;
	pFile->fID_6B=0x6B;
	pFile->fID_B6=0xB6;
	
}
/*
 * @brief  check the file status. if saved, return 1, else return 0;
 */
uint8_t fileIsValidForTrans(uint32_t addr)
{
	TSC_FILE* pFile;
	pFile = (TSC_FILE*)(&FileBufForTrans[addr]);
	
	if(pFile->fID_55!=0x55||pFile->fID_AA!=0xAA||pFile->fID_66!=0x66||pFile->fID_BB!=0xBB||
	   pFile->fID_5A!=0x5A||pFile->fID_A5!=0xA5||pFile->fID_6B!=0x6B||pFile->fID_B6!=0xB6)
		return 0;
	if(pFile->fStatus == FILESAVED)
		return 1;
	return 0;
}
/*
 * @brief  set the file status to <FILESAVED>. 
 */
void setfileStatus(uint32_t addr, uint8_t sts)
{
	TSC_FILE* pFile;
	pFile = (TSC_FILE*)(&FileBufForTrans[addr]);
	
	pFile->fStatus = sts;
}

/*
 * @brief  get the file type at addr. 
 */
uint8_t getfileType(uint32_t addr)
{
	TSC_FILE* pFile;
	pFile = (TSC_FILE*)(&FileBufForTrans[addr]);
	
	return pFile->fType;
}

/*
 * @brief  clear file head
 */
void clearFileHead(uint32_t addr)
{
	uint8_t i;
	
	for(i=0;i<FILEDATAOFFSET;i++)
	{
		FileBufForTrans[addr+i]=0;
	}
}

/*
 * @brief  return file's length at <addr>
 *         because of the format defined in structur TSC_FILE;
 */
uint32_t getFileLength(uint32_t addr)
{
	TSC_FILE* pFile;
	pFile = (TSC_FILE*)(&FileBufForTrans[addr]);
	
	return (uint32_t)(pFile->fLen0 << 0) +
					 (pFile->fLen1 << 8) +
					 (pFile->fLen2 <<16) +
					 (pFile->fLen3 <<24);
}


/*
 * @brief  set file's length at <addr>, fileLen is including the file head.
 */
void setFileLength(uint32_t addr,uint32_t fileLen)
{
	TSC_FILE* pFile;
	pFile = (TSC_FILE*)(&FileBufForTrans[addr]);
	
	pFile->fLen0=(fileLen&0x000000FF)>>0;
	pFile->fLen1=(fileLen&0x0000FF00)>>8;
	pFile->fLen2=(fileLen&0x00FF0000)>>16;
	pFile->fLen3=(fileLen&0xFF000000)>>24;
}

//--------- Global functions -------------------------------------------------------------------
/*
 * @brief  return the begining address of The file that is supposed to send.
 */
uint8_t* getStartAddForSend(void)
{
	return FileBufForTrans+fileReadPtr+FILEDATAOFFSET;
}
/*
 * @brief  return the length of The file that is supposed to send.
 */
uint32_t getFileLenForSend(void)
{
	if(fileIsValidForTrans(fileReadPtr))
		return getFileLength(fileReadPtr);
	else
		return 0;
}
/*
 * @brief  return if there is a file that is free to send.
 */
uint8_t haveFileForSend(void)
{
	if(fileIsValidForTrans(fileReadPtr))
		return 1;
	else
		return 0;
}

/*
 * @brief  handling after a file has been send.
 */
void fileSendCompletedHandler(void)
{
	setfileStatus(fileWritePtr,FILEIVALID);			//set file invalid.
	nextFilePointer(&fileReadPtr,fileWritePtr,1);	//add read pointer
}


/*
 * @brief  return if there is a file that is free to send.
 */
uint8_t haveSpaceForSave(void)
{
	if(fileWriteOffset==FILEDATAOFFSET)//starting saving a new file.
	{
		if(creatNewFile(FILETPYE_A,FILE_DATA_LEN_MAX))
			return 0;
	}
	return 1;
}



